﻿using System;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using AMS.DeDuplicator.BusinessLayer;
using AMS.DeDuplicator.BusinessLayer.Command;
using AMS.DeDuplicator.CommonLayer;
using AMS.DeDuplicator.CommonLayer.Adapter;
using AMS.DeDuplicator.ApplicationLayer.State;

namespace AMS.DeDuplicator.ApplicationLayer
{
    public class FormOperations
    {
        DeDuplicatorClient _client;
        ProgressBar _progressBar;
        Label _progressLabel;
        Stack<Command> _commands; // TODO: expose Undo
        QuickKeys _quickKeys;

        public FormOperations(ProgressBar progressBar, Label progressLabel, TreeViewAdapter tv)
        {
            InputValidator.ValidateNotNull(progressBar);
            _progressBar = progressBar;
            _progressLabel = progressLabel;

            IDuplicateIdentifier identifier = new DuplicateIdentifier(new GetHashValueDelegate(new Sha256Hasher().GetHashValue));
            _client = new DeDuplicatorClient(identifier);
            _client.StartingProcess = new HookDelegate(OperationStarted);
            _client.FinishedFile = new HookDelegate(IncrementProgressBar);
            _client.FinishedProcess = new HookDelegate(OperationComplete);

            _commands = new Stack<Command>();
            _quickKeys = new QuickKeys(tv);
        }

        public void FindDuplicates(string text, ITree populateTargetTree, bool recurse)
        {
            // validate input
            InputValidator.ValidateDirectoryExists(text);

            int fileCount = CountFiles(text, recurse);
            _progressBar.Maximum = fileCount;
            _progressLabel.Text = fileCount.ToString();

            Dictionary<string, List<string>> duplicates = _client.FindDuplicates(text, recurse);

            int popCount = 0;
            foreach (string key in duplicates.Keys)
            {
                popCount++;
                foreach (string str in duplicates[key])
                {
                    popCount++;
                }
            }

            _progressBar.Maximum = popCount;

            OperationStarted(null);
            PopulateTreeView(duplicates, populateTargetTree);
            OperationComplete(null);
        }

        private void PopulateTreeView(Dictionary<string, List<string>> duplicates, ITree tree)
        {
            tree.Nodes.Clear();

            foreach (string first in duplicates.Keys)
            {
                TreeNode rootNode = tree.Nodes.Add(first);
                IncrementProgressBar(null);

                foreach (string duplicate in duplicates[first])
                {
                    rootNode.Nodes.Add(duplicate);
                    IncrementProgressBar(null);
                }
            }
        }

        private int CountFiles(string directory, bool recurse)
        {
            DirectoryInfo dirInfo = new DirectoryInfo(directory);
            return CountFiles(dirInfo, recurse);
        }

        private int CountFiles(DirectoryInfo directory, bool recurse)
        {
            int result = directory.GetFiles().Length;
            if (recurse)
            {
                foreach (DirectoryInfo dir in directory.GetDirectories())
                {
                    result += dir.GetFiles().Length;
                    result += CountFiles(dir, recurse);
                }
            }

            return result;
        }

        public bool DeleteDuplicates(TreeViewAdapter treeViewAdapter, bool replaceWithShortcuts)
        {
            InputValidator.ValidateNotNull(treeViewAdapter);

            //encapsulate this in one command
            //iterate thru treeViewAdapter for all checked files
            //delete each file
            //create shortcut to origin file with name of deleted file and put in place of deleted file
            Command cmd = new DeleteReplaceFacade(treeViewAdapter.GetNonRootIterator());
            bool successful = cmd.Execute();
            _commands.Push(cmd);
            return successful;
        }

        public void OpenFile(string filePath)
        {
            new OpenFileCommand(filePath).Execute();
        }

        public void ClearTemp()
        {
            new ClearTempCommand().Execute();
        }

        internal void ProcessKeyDown(Keys key)
        {
            _quickKeys.ProcessInput(key);
        }

        private void OperationStarted(object o)
        {
            _progressBar.Value = 0;
            _progressBar.Visible = true;
            _progressLabel.Text = String.Format("{0} out of {1}", _progressBar.Value.ToString(), _progressBar.Maximum.ToString());
            _progressLabel.Visible = true;
        }

        private void IncrementProgressBar(object o)
        {
            _progressBar.Increment(1);
            _progressLabel.Text = String.Format("{0} out of {1}", _progressBar.Value.ToString(), _progressBar.Maximum.ToString());
            
            // TODO: replace this with threading
            Application.DoEvents();
            //_progressBar.Update();
        }

        private void OperationComplete(object o)
        {
            _progressBar.Value = 0;
            _progressBar.Visible = false;
            _progressLabel.Text = string.Empty;
            _progressLabel.Visible = false;
        }
    }
}
